// -*- c-basic-offset: 2 default-tab-width: 2 indent-tabs-mode: t -*-
// vim: autoindent tabstop=2 noexpandtab shiftwidth=2 softtabstop=2
/*
 * REnvs.cpp
 *
 *  Created on: Dec 12, 2011
 *      Author: bakiras
 */

#include "Environment.h"
#include "Const.h"
#include "Promise.h"
#include "Bindings.h"
#include "Closure.h"

using namespace R;

#pragma warning "Environment ** is not gcrooted !"
Any* CollectableEnvironment::getVar(Symbol *sym, Environment** def, bool* has) {
	R_PARAM(sym);
	R_VAR(Any*, res);
	int  i;

	if((i = bindings->resolve(sym)) != -1) {
		*has = 1;
		return bindings->get(i);
	}

	if(fun) {
		res = fun->getVar(sym, has);
		if(*has) {
			if(def)
				*def = this;
			return res;
		}
	}

	if(enclosing)
		return enclosing->getVar(sym, def, has);
	else
		return 0;
}

r_bool CollectableEnvironment::exists(Symbol *sym) {
	R_PARAM(sym);

  uint64_t i = bindings->resolve(sym);
  return (i == -1) ? false : true;
}

void CollectableEnvironment::setOrCreateLocalVar(Symbol *sym, Any *value){
  R_PARAM(sym);
  R_PARAM(value);

  uint64_t i = bindings->resolve(sym);
  if(i != -1)
	  bindings->set(i, value);
	else
		createLocalVar(sym, value);
}

void CollectableEnvironment::createLocalVar(Symbol *sym, Any *value){
  R_PARAM(sym);
  R_PARAM(value);

//	Assert(!idx);

	bindings = bindings->expand(sym, value, 0);
}

Environment* CollectableEnvironment::hidden_doNew(Environment* parent, FunInfo *fun) {
	R_PARAM(parent);
	R_VAR(CollectableEnvironment*, res);

	int len = fun->writeSet.size();
	res = static_cast<CollectableEnvironment*>(operator new(sizeof(CollectableEnvironment) + len*sizeof(Any*) - sizeof(Any*), CollectableEnvironment::virtualVT));
	//res->bindings = NULL; // Bindings::create(fun->writeSet.size());
	res->enclosing = parent;
	res->fun = fun;
	return res;
}

Environment* Environment::makeTopLevel() {
	return CollectableEnvironment::makeTopLevel();
}

Environment* CollectableEnvironment::makeTopLevel() {
	R_VAR(CollectableEnvironment*, res);
	res = static_cast<CollectableEnvironment*>(operator new(sizeof(CollectableEnvironment) - sizeof(Any*), CollectableEnvironment::virtualVT));
	return res;
}

Environment* Environment::doNew(Environment* parent, FunInfo *fun) {
	R_PARAM(parent);
	R_VAR(Environment*, e);

//	Assert(!parentIdx);
	if(!fun || fun->hasClosure || 1) { // FIXME When non GC envs will be implemented
		e = CollectableEnvironment::hidden_doNew(parent, fun);
		Assert(e->fun);
		return e;
	} else {
		nyi_fatal();
		return 0;
	}
}

void Environment::doRelease(uint64_t idx) {
// FIXME	if(stackEnv == env) {
//		nyi_fatal();
//	} else
		Assert(!idx);
}

Any* EnvInfo::getVar(Symbol *sym, bool* has, bool pushInfo) {
	R_PARAM(sym);
	R_VAR(Any*, res);
	R_VAR(Environment*, defEnv);
	if(isGc) {
		res = env_gc->getVar(sym, &defEnv, has);
		if(pushInfo)
			stack->pushTopLevel(defEnv);
		return res;
	}	else {
		nyi_fatal();
	}
	return NULL;
}

void EnvInfo::inspect() {
	if(isGc){
		env_gc->inspect();
	} else {
		nyi_fatal();
	}
}

r_bool EnvInfo::exists(Symbol *sym) {
	R_PARAM(sym);
	if(isGc){
		return env_gc->exists(sym);
	} else {
		nyi_fatal();
	}
}

void EnvInfo::print() {
	if(isGc){
		env_gc->print();
	} else {
		nyi_fatal();
	}
}

void EnvInfo::setOrCreateLocalVar(Symbol *sym, Any *value) {
	R_PARAM(sym);
	R_PARAM(value);
	if(isGc){
		env_gc->setOrCreateLocalVar(sym, value);
	}else{
		nyi_fatal();
	}
}

void EnvInfo::createLocalVar(Symbol *sym, Any *value){
	R_PARAM(sym);
	R_PARAM(value);
	if(isGc){
		env_gc->createLocalVar(sym, value);
	}else{
		nyi_fatal();
	}
}
